package com.kkb.kkbportal.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.kkb.kkbcommon.constant.SystemConstants;
import com.kkb.kkbcommon.exception.ApiException;
import com.kkb.kkbcommon.exception.Asserts;
import com.kkb.kkbportal.dao.UserMapper;
import com.kkb.kkbportal.dao.UserRoleMapper;
import com.kkb.kkbportal.domain.dto.UserDto;
import com.kkb.kkbportal.domain.ums.User;
import com.kkb.kkbportal.service.ScoreService;
import com.kkb.kkbportal.service.UserService;
import com.kkb.kkbportal.service.util.SmsUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;


/**
 * @author
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    UserRoleMapper userRoleMapper;
    @Autowired
    private ScoreService scoreService;
    @Autowired
    private UserService userService;

    @Autowired
    private RedisTemplate redisTemplate;


    /**
     * 根据传入的手机号和密码进行登录验证
     *
     * @param condition 条件
     */
    @Override
    public void userLogin(User condition) {
        User user = selectByPhoneNumber(condition.getPhoneNumber());
        boolean flag = condition.getPassword().equals(user.getPassword());
        if (!flag) {
            Asserts.fail("登录失败");
        }
    }

    /**
     * 根据传入的手机号发送验证码
     *
     * @param phoneNumber 手机号
     */
    @Override
    public void forgetPassword(String phoneNumber) {
        //先根据手机号查询是否有此用户
        User user = selectByPhoneNumber(phoneNumber);
        //TODO:完成短信发送的流程
        //生成6位数的随机数
        long code = (long) (Math.random() * 899999) + 100000;
        try {
            //发送短信
            SendSmsResponse sendSms = SmsUtils.sendSms(phoneNumber, String.valueOf(code));
            //输出验证码（测试使用）
            System.out.println(phoneNumber + ": 的验证码为：" + code);
            /*
                将手机号和对应的验证码存入Redis -> namespace = smsCode
                                                 - phoneNumber code
            */
            redisTemplate.boundHashOps(SystemConstants.TEMPLATE_SMS_CODE).put(phoneNumber, String.valueOf(code));
        } catch (ClientException e) {
            e.printStackTrace();
            Asserts.fail("短信发送失败");
        }
    }

    /**
     * 根据手机号和验证码登录
     *
     * @param phoneNumber 手机号
     * @param password    验证码
     * @return 登录用户对象
     */
    @Override
    public Boolean passwordIsRight(String phoneNumber, String password) {
        //todo: 改成userService形式，使用mybatisPlus
        String rightPassword = "";
        return rightPassword.equals(password);
    }

    /**
     * 发短信
     *
     * @param phoneNumber
     * @param code
     * @return
     */
    @Override
    public User smsCodeVerify(String phoneNumber, String code) {
        //从Redis根据 namespace 和手机号获取验证码
        String codeInRedis = (String) redisTemplate.boundHashOps(SystemConstants.TEMPLATE_SMS_CODE).get(phoneNumber);
        if (codeInRedis == null || !codeInRedis.equals(code)) {
            Asserts.fail("验证码错误");
        }
        //验证通过后从Redis里删除手机号和验证码
        redisTemplate.boundHashOps(SystemConstants.TEMPLATE_SMS_CODE).delete(phoneNumber);
        return getBaseMapper().selectOne(Wrappers.<User>query().eq("phone_number", phoneNumber));
    }

    /**
     * 根据传入的手机号和密码进行注册验证插入
     *
     * @param condition 注册的用户信息
     */
    @Override
    public void userRegister(User condition) {
        try {
            //如果传进去电话号码不存在数据库，就会主动抛异常；存在数据库才会返回user。但我要的效果就是电话号码不存在后主动抛异常。
            selectByPhoneNumber(condition.getPhoneNumber());
        } catch (ApiException e) {
            boolean flag = save(condition);
            if (!flag) {
                Asserts.fail("注册失败");
            }
        }
    }

    /**
     * 根据用户id查询用户信息
     *
     * @param id 用户id
     * @return 用户信息
     */
    @Override
    public User selectUserById(Long id) {
        User user = this.getById(id);
        if (ObjectUtil.isNull(user)) {
            Asserts.fail("查无此用户");
        }
        return user;
    }

    /**
     * 根据id删除用户
     *
     * @param id 用户id
     */
    @Override
    public void deleteById(Long id) {
        User user = this.getById(id);
        if (ObjectUtil.isNull(user)) {
            Asserts.fail("查无此用户");
        }
        boolean flag = removeById(id);
        if (!flag) {
            Asserts.fail("删除失败");
        }
    }

    /**
     * 根据手机号密码查询登录
     *
     * @param phoneNumber 条件
     */
    @Override
    public User selectByPhoneNumber(String phoneNumber) {
        User user = this.lambdaQuery()
                .eq(User::getPhoneNumber, phoneNumber).one();
        if (ObjectUtil.isNull(user)) {
            Asserts.fail("查无此号");
        }
        return user;
    }


    /**
     * 根据导师/学员id，查询基本个人信息
     *
     * @param id 导师/学员id
     * @return 基本个人资料
     * @author syt group-1
     */
    @Override
    public UserDto selectUserInfoById(Long id) {
        // 根据用户id，查询对象
        User user = this.getById(id);
        if (ObjectUtil.isNull(user)) {
            Asserts.fail("没有该用户");
        }
        // 赋值给Dto
        return UserDto.builder()
                .id((user.getId()))
                .headUrl(user.getHeadUrl())
                .name(user.getName())
                .job(user.getJob())
                .skill(user.getSkill())
                .projectInfo(user.getProjectInfo())
                .dailySalary(user.getDailySalary())
                .build();
    }


    /**
     * 根据id修改用户信息
     *
     * @param id   用户id
     * @param user 修改后的用户信息
     */
    @Override
    public void updateById(Long id, User user) {
        User oldUser = this.getById(id);
        if (ObjectUtil.isNull(oldUser)) {
            Asserts.fail("查无此用户");
        }
        user.setId(id);
        boolean flag = updateById(user);
        if (!flag) {
            Asserts.fail("修改失败");
        }
    }

    /**
     * 根据条件查询用户数据列表
     *
     * @param condition 条件
     * @return
     */
    @Override
    public List<User> selectByCondition(User condition) {
        List<User> list = this.lambdaQuery()
                .eq(ObjectUtil.isNotNull(condition.getId()), User::getId, condition.getId())
                .like(StrUtil.isNotBlank(condition.getPhoneNumber()), User::getPhoneNumber, condition.getPhoneNumber())
                .like(StrUtil.isNotBlank(condition.getName()), User::getName, condition.getName())
                .like(StrUtil.isNotBlank(condition.getWechat()), User::getWechat, condition.getWechat())
                .eq(ObjectUtil.isNotNull(condition.getDailySalary()), User::getDailySalary, condition.getDailySalary())
                .eq(ObjectUtil.isNotNull(condition.getWorkingYear()), User::getWorkingYear, condition.getWorkingYear()).list();
        return list;
    }

    /**
     * 可以根据条件查询分页用户数据
     *
     * @param condition 条件
     * @param pageNum   当前页码
     * @param pageSize  每页页数
     */
    @Override
    public PageInfo<User> selectPage(User condition, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        PageInfo<User> pageInfo = new PageInfo<>(this.selectByCondition(condition));
        return pageInfo;
    }

    /**
     * 根据用户 id 和角色 id 添加用户角色关系
     *
     * @param uid 用户id
     * @param rid 角色id
     */
    @Override
    public void selectRoleByUserId(Long uid, Long rid) {
        //先查询是否存在此对应关系
        Long userRoleId = userRoleMapper.selectByUserIdAndRoleId(uid, rid);
        if (userRoleId != null) {
            Asserts.fail("当前用户已经拥有此角色");
        }
        int flag = userRoleMapper.insertUserAndRole(uid, rid);
        if (flag == 0) {
            Asserts.fail("添加用户角色关系失败");
        }
    }
}
